package com.demo;

import com.demo.util.CamelUtils;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.io.File;
import java.io.FileWriter;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 生成dto 好未来
 * @author gy
 * @date 2025/3/2
 */
public class GeneratorDTOTalEval {

    @Test
    public void generator() throws Exception {
        long startTime = System.currentTimeMillis();

        this.generatorInputDTOTal();
        this.generatorSelectInputDTOTal();
        this.generatorOutputDTOTal();

        long endTime = System.currentTimeMillis();
        System.out.println("总计耗时["+(endTime - startTime)+"]毫秒");
    }

    // todo 设定要生成的表
//    private static final String tableName = "eval_model_result";
//    private static final String tableName = "eval_mark_user";
//    private static final String tableName = "subject_dict";
//    private static final String tableName = "static_content";
//    private static final String tableName = "indicator_dict";
    private static final String tableName = "eval_task";
//    private static final String tableName = "eval_score";
//    private static final String tableName = "eval_dimension_indicator";
//    private static final String tableName = "eval_dataset";
//    private static final String tableName = "dimension_dict";
//    private static final String tableName = "user";
//    private static final String tableName = "param_test";
    
    

    // todo 设定包名
//    private static final String packageInfo = "com.tal.mathgpt";
    private static final String packageInfo = "com.bnueval.edueval";

    private static final String srcPath = "/Users/tal/Develop/generator/src/main/java/" +
            packageInfo.replace(".","/");
//    private static final String srcPath = "/Users/tal/Develop/mathgpt_project/mathgpt-at-server/src/main/java/" +
//            packageInfo.replace(".","/");
//        private static final String srcPath = "/Users/tal/Develop/edueval_project/edueval-server/src/main/java/" +
//            packageInfo.replace(".","/");

    // todo 修改全局配置
    private static final String author = "gy";
    private static final boolean swaggerFlag = false;


//    ------------------------------数据源配置 start --------------------------------------------
    private static final String driver="com.mysql.cj.jdbc.Driver";

    private static final String ipAddrAndPort="10.202.5.130:3306";

//    private static final String dbCatalog = "spier_data";
//    private static final String dbCatalog = "at_open";
    private static final String dbCatalog = "edu_eval";

    private static final String username="rdsroot";

    private static final String password="xxx";

    private static final String serverUrl ="jdbc:mysql://"+ipAddrAndPort+"?" +
            "useSSL=false&useUnicode=true&characterEncoding=utf8&autoReconnect=true" +
            "&rewriteBatchedStatements=TRUE&serverTimezone=Asia/Shanghai&allowMultiQueries=true" +
            "&useInformationSchema=true";//没有指定具体哪个数据库，现在获取的是整个连接
    private static final String url="jdbc:mysql://"+ipAddrAndPort+"/"+dbCatalog+"?" +
            "charset=utf8mb4&autoReconnect=true&zeroDateTimeBehavior=CONVERT_TO_NULL&" +
            "serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&useUnicode=yes";//指定 dbCatalog 数据库

//    ------------------------------数据源配置 end --------------------------------------------

    private static final String tableNamePrefix = "t_";

    private static final String entityInputDTOSuffix="InputDTO";
    private static final String entityOutputDTOSuffix="OutputDTO";

    private static final String fileType = ".java";

    private static final String entityName = CamelUtils.line2upperCamel(tableName);

    private static final String entityClassPackage=packageInfo+".entity."+entityName;

    private static final String inputPackagePath=srcPath + "/dto/input/";
    private static final String inputDTOClassPackage=packageInfo + ".dto.input";

    private static final String pageParamPackage =packageInfo + ".dto.PageParam";
    private static final String ParamGroupDTOPackage =packageInfo + ".dto.ParamGroupDTO";
    private static final String selectPackagePath=srcPath + "/dto/input/";
    private static final String entityInputDTOPrefix="Select";

    private static final String outputPackagePath=srcPath + "/dto/output/";
    private static final String outputDTOClassPackage=packageInfo + ".dto.output";


    @Test
    public void generatorInputDTOTal() throws Exception {
        long startTime = System.currentTimeMillis();
        //1，创建FreeMarker的配置类
        Configuration cfg=new Configuration();
        //2，指定模板加载器，将模板加入缓存中
        //文件路径加载器，获取到templates文件的路径
        String templates = this.getClass().getClassLoader().getResource("templates").getPath();
        FileTemplateLoader fileTemplateLoader=new FileTemplateLoader(new File(templates));
        cfg.setTemplateLoader(fileTemplateLoader);
        //3，获取模板
        Template template = cfg.getTemplate("EntityInputDTOTal.ftl");

        //4，构造数据模型
        Map<String, Object> map = buildModel();

        //5，文件输出
        /**
         * 处理模型
         *      参数一 数据模型
         *      参数二 writer对象（FileWriter（文件输出），printWriter（控制台输出））
         */
        System.out.println("-----------------生成 EntityInputDTO 开始-----------------------");

        // 如果dto路径不存在，先创建
        File dir = new File(inputPackagePath.substring(0,inputPackagePath.length()-1));
        if(!dir.exists()){
            dir.mkdirs();//创建目录
        }
        File file = new File(inputPackagePath+entityName+entityInputDTOSuffix+fileType);
        // 如果存在，就删除旧的文件，保证是最新生成的文件
        if (file.exists()) {
            file.delete();
        }

        template.process(map,new FileWriter(
                new File(inputPackagePath+entityName+entityInputDTOSuffix+fileType)));

        System.out.println("***EntityInputDTO文件位置："+inputPackagePath+entityName+entityInputDTOSuffix+fileType);
        System.out.println("-----------------生成 EntityInputDTO 结束-----------------------");
        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }

    @Test
    public void generatorSelectInputDTOTal() throws Exception {
        long startTime = System.currentTimeMillis();

        //1，创建FreeMarker的配置类
        Configuration cfg=new Configuration();
        //2，指定模板加载器，将模板加入缓存中
        //文件路径加载器，获取到templates文件的路径
        String templates = this.getClass().getClassLoader().getResource("templates").getPath();
        FileTemplateLoader fileTemplateLoader=new FileTemplateLoader(new File(templates));
        cfg.setTemplateLoader(fileTemplateLoader);
        //3，获取模板
        Template template = cfg.getTemplate("SelectEntityInputDTOTal.ftl");

        //4，构造数据模型
        Map<String, Object> map = buildModel();

        //5，文件输出
        /**
         * 处理模型
         *      参数一 数据模型
         *      参数二 writer对象（FileWriter（文件输出），printWriter（控制台输出））
         */

        System.out.println("-----------------生成 SelectEntityInputDTO 开始-----------------------");

        // 如果dto路径不存在，先创建
        File dir = new File(selectPackagePath.substring(0,selectPackagePath.length()-1));
        if(!dir.exists()){
            dir.mkdirs();//创建目录
        }
        File file = new File(selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType);
        // 如果存在，就删除旧的文件，保证是最新生成的文件
        if (file.exists()) {
            file.delete();
        }

        template.process(map,new FileWriter(selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType));


        long endTime = System.currentTimeMillis();
        System.out.println("***SelectEntityInputDTO文件位置："+selectPackagePath+entityInputDTOPrefix+entityName+entityInputDTOSuffix+fileType);
        System.out.println("-----------------生成 SelectEntityInputDTO 结束-----------------------");

        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }

    @Test
    public void generatorOutputDTOTal() throws Exception {
        long startTime = System.currentTimeMillis();
        //1，创建FreeMarker的配置类
        Configuration cfg=new Configuration();
        //2，指定模板加载器，将模板加入缓存中
        //文件路径加载器，获取到templates文件的路径
        String templates = this.getClass().getClassLoader().getResource("templates").getPath();
        FileTemplateLoader fileTemplateLoader=new FileTemplateLoader(new File(templates));
        cfg.setTemplateLoader(fileTemplateLoader);
        //3，获取模板
        Template template = cfg.getTemplate("EntityOutputDTOTal.ftl");

        //4，构造数据模型
        Map<String, Object> map = buildModel();

        //5，文件输出
        /**
         * 处理模型
         *      参数一 数据模型
         *      参数二 writer对象（FileWriter（文件输出），printWriter（控制台输出））
         */
        System.out.println("-----------------生成 EntityOutputDTO 开始-----------------------");

        // 如果dto路径不存在，先创建
        File dir = new File(outputPackagePath.substring(0,outputPackagePath.length()-1));
        if(!dir.exists()){
            dir.mkdirs();//创建目录
        }

        File file = new File(outputPackagePath+entityName+entityOutputDTOSuffix+fileType);
        // 如果存在，就删除旧的文件，保证是最新生成的文件
        if (file.exists()) {
            file.delete();
        }

        template.process(map,new FileWriter(
                new File(outputPackagePath+entityName+entityOutputDTOSuffix+fileType)));

        System.out.println("***EntityOutputDTO文件位置："+outputPackagePath+entityName+entityOutputDTOSuffix+fileType);
        System.out.println("-----------------生成 EntityOutputDTO 结束-----------------------");
        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时["+(endTime - startTime)+"]毫秒");
    }


    /**
     * # sql类型和java类型的替换规则
     */
    private final static HashMap<String,String> typeConverterMap = new HashMap<>();
    static {
        typeConverterMap.put("BIGINT","Long");
        typeConverterMap.put("INT UNSIGNED","Integer");
        typeConverterMap.put("NUMBER","Long");
        typeConverterMap.put("INT","Integer");
        typeConverterMap.put("TINYINT","Integer");
        typeConverterMap.put("BIT","Integer");
        typeConverterMap.put("DATE","Date");
        typeConverterMap.put("DATETIME","LocalDateTime");
        typeConverterMap.put("DOUBLE","Double");
        typeConverterMap.put("FLOAT","Float");
        typeConverterMap.put("DECIMAL","BigDecimal");
        typeConverterMap.put("VARCHAR","String");
        typeConverterMap.put("VARCHAR2","String");
        typeConverterMap.put("NVARCHAR2","String");
        typeConverterMap.put("CHAR","String");
        typeConverterMap.put("TEXT","String");
        typeConverterMap.put("LONGTEXT","String");
        typeConverterMap.put("JSON","JSONObject");
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Field {
        /**
         * mysql_column_name
         */
        private String name;
        /**
         * mysql_column_remarks 字段注释
         */
        private String remark;
        /**
         * javaColumnName
         */
        private String propertyName;
        /**
         * mysql_type_name
         */
        private String typeName;
        /**
         * javaTypeName
         */
        private String propertyType;
        /**
         * mysql_column_size
         */
        private String columnSize;
    }


    /**
     * 构造数据模型
     * @return
     */
    private Map<String, Object> buildModel() throws Exception {

        //获取连接
        Class.forName(driver);//注册驱动
        Connection connection = DriverManager.getConnection(url, username,password);

        //获取元数据
        DatabaseMetaData metaData = connection.getMetaData();
        //获取数据库中表信息（mysql可以这样写，oracle会有一点区别）
        //参数1：当前操作的数据库 参数2：mysql可为空，oracle填写用户名（要大写） 参数3：null是查询所有表 非空是查询目标表 参数4：类型 table是表，view是视图
        ResultSet resultSet = metaData.getTables(dbCatalog, null, tableName, new String[]{"TABLE"});

        String TABLE_NAME = null;
        String REMARKS = null;
        while (resultSet.next()){
            //会打印出该数据库下的所有表名
            String TABLE_CAT = resultSet.getString("TABLE_CAT");
            String TABLE_SCHEM = resultSet.getString("TABLE_SCHEM");
            TABLE_NAME = resultSet.getString("TABLE_NAME");
            String TABLE_TYPE = resultSet.getString("TABLE_TYPE");
            REMARKS = resultSet.getString("REMARKS");
//            System.out.printf("表类别:%s, 表模式:%s, 表名称:%s, 表类型:%s, 表描述:%s\n",
//                    TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE,REMARKS);
        }


        Map<String,Object> map=new HashMap<String, Object>();
        map.put("tableName",TABLE_NAME);
        map.put("entity",entityName);
        map.put("tableComment",REMARKS);

        String createDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        map.put("createDate",createDate);
        map.put("author",author);
        map.put("swaggerFlag",swaggerFlag);

        HashMap<String, Object> packageMap = new HashMap<>();
        packageMap.put("outputDTOClassPackage",outputDTOClassPackage);
        packageMap.put("inputDTOClassPackage",inputDTOClassPackage);
        packageMap.put("entityClassPackage",entityClassPackage);
        packageMap.put("PageParamPackage", pageParamPackage);
        packageMap.put("ParamGroupDTOPackage", ParamGroupDTOPackage);

        map.put("package",packageMap);


        ResultSet columns = metaData.getColumns(dbCatalog, null, tableName, null);
        ArrayList<Field> fields = new ArrayList<>();
        while (columns.next()){
            String mysql_column_name = columns.getString("COLUMN_NAME");
            String mysql_column_remarks = columns.getString("REMARKS");
            String javaColumnName = CamelUtils.line2lowerCamel(mysql_column_name);
            String mysql_type_name = columns.getString("TYPE_NAME");
            String javaTypeName = typeConverterMap.get(mysql_type_name);
            String mysql_column_size = columns.getString("COLUMN_SIZE");

            //会打印出指定表的所有字段名
//            System.out.println(mysql_column_name + " "+javaColumnName +" "+mysql_type_name + " "+javaTypeName
//                    + " "+mysql_column_size+ " "+mysql_column_remarks);

            Field field = new Field();
            field.setName(mysql_column_name);
            field.setRemark(mysql_column_remarks);
            field.setPropertyName(javaColumnName);
            field.setPropertyType(javaTypeName);

            field.setTypeName(mysql_type_name);
            field.setColumnSize(mysql_column_size);

            fields.add(field);
        }

        // 添加字段信息
        map.put("fields",fields);


        resultSet.close();
        connection.close();

        return map;
    }



}
